<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>分支切换与cleanup</title>
</head>
<body>
  <div id="app"></div>
  <div id="app1"></div>
  <div id="app2"></div>
<script>
function reactive(data) {
  return new Proxy(data, {
    get(target, key, receive) {
      const res = Reflect.get(target, key, receive)
      track(target, key)
      return res
    },
    set(target, key, newValue, receive) {
      const res = Reflect.set(target, key, newValue, receive)
      trigger(target, key)
      return res
    }
  })
}
//依赖存储器
const bucket = new WeakMap() //obj->k->set

function track(target, key) {
  if (!activeEffect) return
  let depsMap = bucket.get(target)
  if (!depsMap) {
    depsMap = new Map()
    bucket.set(target, depsMap)
  }
  let deps = depsMap.get(key)
  if (!deps) {
    deps = new Set()
    depsMap.set(key, deps)
  }
  deps.add(activeEffect)
  console.table('key->',key,'deps->',deps,)
  activeEffect.deps.push(deps)
  console.log('activeEffect->', activeEffect)
  console.log('activeEffect.deps->',activeEffect.deps)
}

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const deps = new Set(depsMap.get(key))
  deps && deps.forEach((fn) => {
    if(fn !== activeEffect) {
      fn()
    }
  })
}

let activeEffect = null

function effect(fn, options) {
  const effectFn = ()=> {
    console.log('effectFn.deps->',effectFn.deps, effectFn.deps.length)
    cleanup(effectFn)
    activeEffect = effectFn
    fn()
  }
  
  effectFn.deps = []
  effectFn()
}

function cleanup(effectFn) {
  const {deps} = effectFn
  for(let i = 0; i < deps.length; i++ ) {
    console.log('deps[i]',deps[i],deps[i].has(effectFn), deps[i].size)
    deps[i].delete(effectFn)
  }
  effectFn.deps.length = 0
}
    
</script>

 <script>
  const data = {
    ok: true,
    text: 'hello world',
    foo: 1
  }
  const obj = reactive(data)
  effect(()=>{
    document.getElementById('app').innerText = obj.ok ? obj.text : 'not'
    console.log('effect1')
  })
  effect(()=>{
    document.getElementById('app1').innerText = obj.text
    console.log('effect2')
  })
  effect(()=>{
    document.getElementById('app2').innerText = obj.foo
    console.log('effect3')
  })
 </script>
</body>
</html>